//
//  AVGData.cpp
//  Chart
//
//  Created by CaoJun on 13-6-3.
//
//

#include "AVGData.h"
#include "Metal.h"
#include "config.h"
#include "YTXChartTools.h"
#include "Quotation.h"
#include "YTXChartCommon.h"

#include <vector>
#include <map>
#include <limits>
#include <numeric>
#include <cmath>


#import <DateTools/DateTools.h>//debug

using namespace ytx;
using namespace std;


AVGData::AVGData(string id, string currentDate, string marketType, int toFix, string name, string nickName, YTXTime openTime, YTXTime closeTime, int dataSum, bool hasVolume, TimeString timeString, Rect row, Rect column, vector<pair<YTXTime, YTXTime> > restTime) :
Quotation(id, currentDate, LineType::LAVG, marketType, hasVolume, toFix), calTimeString(timeString)
, UserGraphInterface(id, LineType::LAVG)
, IndexConfigInterface(id, LineType::LAVG)
, economicCalendarDataFlag(false)
,restTime(restTime)
,tradedate(YTXTime::not_a_date_time())
,nextTradedate(YTXTime::not_a_date_time())
,nextTradedateStartTime(YTXTime::not_a_date_time())
,nextTradedateEndTime(YTXTime::not_a_date_time())
,exitDataCount(0)
,addDay(0)
,baseDrawCount(Config::getInstance()->AVG.len),
quotedPriceFlag(false),
biddingTime(0),
prevAVGData(NULL)
{
    Style style = Config::getInstance()->style;

    lineData.push_back(vector<double>());
    lineData.push_back(vector<double>());
    prevValue = numeric_limits<double>::quiet_NaN();

    setAddDay(0);
    setQuotationName(name);
    setOpenTime(openTime);
    setCloseTime(closeTime);
    setNickName(nickName);
    setMarketType(marketType);

    setType(QuotationType::AVG);
    setUpdateTime("");

    setBaseDrawCount(dataSum);
    setDrawingCount(dataSum);
    vector<string> titleType;
    titleType.push_back(style.avgAVEColor);
    titleType.push_back(style.avgAVEName);
    titleType.push_back(style.avgValueColor);
    titleType.push_back(style.avgValueName);
    titleType.push_back(style.avgUpDropColor);//涨跌幅颜色
    titleType.push_back(style.avgPercentColor);//涨跌率颜色
    setTitleType(titleType);
    setTimeString(timeString.big);
    setOriginTimeString(timeString);
    setColumn(column);
    setRow(row);
    setOriginRow(row);
    setOriginColumn(column);

    if (marketType == "SGE") {
        biddingTime = 10;
    }

    quotedPrice.open = std::numeric_limits<double>::quiet_NaN();

}

AVGData::AVGData(AVGData * avgData) :
Quotation(avgData->id, avgData->currentDate, LineType::LAVG, avgData->marketType, avgData->hasVolume, avgData->toFix), calTimeString(avgData->calTimeString), restTime(avgData->restTime),tradedate(YTXTime::not_a_date_time())
, UserGraphInterface(id, LineType::LAVG)
, IndexConfigInterface(id, LineType::LAVG)
, nextTradedate(YTXTime::not_a_date_time())
, nextTradedateStartTime(YTXTime::not_a_date_time())
, nextTradedateEndTime(YTXTime::not_a_date_time())
, exitDataCount(0),addDay(0),baseDrawCount(Config::getInstance()->AVG.len), quotedPriceFlag(false),
prevAVGData(NULL),
economicCalendarDataFlag(false)
{
    Style style = Config::getInstance()->style;

    lineData.push_back(vector<double>());
    lineData.push_back(vector<double>());
    prevValue = numeric_limits<double>::quiet_NaN();

    setAddDay(0);
    setQuotationName(avgData->QuotationName);
    setOpenTime(avgData->openTime);
    setNickName(avgData->nickName);

    dateRuler = avgData->dateRuler;
    setMarketType(avgData->marketType);

    setType(QuotationType::AVG);
    setHasVolume(avgData->hasVolume);
    setUpdateTime("");
    setBaseDrawCount(avgData->baseDrawCount);
    vector<string> titleType;
    titleType.push_back(style.avgValueColor);
    titleType.push_back(style.avgValueName);
    titleType.push_back(style.avgAVEColor);
    titleType.push_back(style.avgAVEName);
    titleType.push_back(style.avgUpDropColor);//涨跌幅颜色
    titleType.push_back(style.avgPercentColor);//涨跌率颜色
    setTitleType(titleType);
    setTimeString(avgData->timeString);
    setOriginTimeString(avgData->originTimeString);
    setColumn(avgData->column);
    setOriginRow(avgData->originRow);
    setOriginColumn(avgData->originColumn);
}

AVGData::~AVGData()
{
    clearAllData();
    // Quotation::~Quotation();
}

void AVGData :: requestData(const string tag, const DataOption & dataOption, const string acceptableContent)
{
    fire("request.start", NULL);
    Quotation::requestData(tag, dataOption, acceptableContent);
}

void AVGData::firstFailRequestHandler(string tag)
{
    if (tag == "requestAvg" && !hasData())
    {
        fire("firstFail", NULL);
    }
    else if (tag == "requestDataByTradeDate")
    {
        fire("firstFail", NULL);
    }
}

void AVGData::callback(string tag, string data)
{
    YTXJson::Reader reader;
    YTXJson::Value value;

    try {
        if(reader.parse(data, value))
        {
            YTXJson::Value datas = value["data"], info = value["Comm"];
            string msg = value["errorMsg"].asString();
            fire("request.stop", NULL);
            if(tag == "requestAvg"){
                responseAvg(datas, info);
            }
            else if (tag == "requestPrevData"){
                responsePrevData(datas, info);
            }
            else if (tag == "requestEconomicCalendarDataList"){
                responseEconomicCalendarDataList(value);
            }
            else if (tag == "requestAvgLSP"){
                responseAvgLSP(value, value["info"]);
            }
        }
    } catch (void * __attribute__((annotate("oclint:suppress[unused local variable]"))) ex) {
        fire("request.stop", NULL);
    }

}

void AVGData::onFail(string tag)
{
    fire("request.stop", NULL);
    fire(tag+".stop", NULL);
}

UpDropStatus::UpDropStatus AVGData::getUpDropStatus(int index)
{
    // volume画图使用得到 所以一直是 Balance
//    return UpDropStatus::Balance;
        if (hasData()) {
            double v = lineData[0][index];
            double formerPrice = index==0 ? prevValue : lineData[0][index-1];
            
            if(v < formerPrice){
                return UpDropStatus::Drop;
            }
            else if(v == formerPrice){
                return UpDropStatus::Balance;
            }
            else{
                return UpDropStatus::Up;
            }
        }
        else{
            return UpDropStatus::Drop;
        }
}

std::string AVGData::getCrosshairYData(int index)
{
    index = fixIndexRange(index);
    return Tools::Convert2FixString(lineData[0][index], toFix);
}

void AVGData::requestAvg(string tag)
{
    //    int len = this->getDataLength();
    bool isNewTradeDay = this->isNewTradeDay();
    //CHECK: getUpdateTime, already GTM8
//    string updateTime =  (isNewTradeDay || !hasData()) ? "0" : getUpdateTime();
    bool isFirstRequest = (isNewTradeDay || !hasData());
    //CHECK: 上海金
    if(isNewTradeDay){
        clearAllData();
        fire("avgData.newTradeDay", NULL);
    }
#warning 交易时间待延长...
    if (todayIsFinish() && !isNewTradeDay) {
        return;
    }

    map<string, string> urlOption;
//    urlOption.insert(pair<string, string>("quotationType", "1"));
    urlOption.insert(pair<string, string>("Ei", id));
    urlOption.insert(pair<string, string>("QryTm", isFirstRequest ? "0" : getUpdateTime()));

    
    urlOption.insert(pair<string, string>("Sort", isFirstRequest ? "lt" : "gt"));
    urlOption.insert(pair<string, string>("Period", "1"));
    DataOption option = createOption(urlOption, Config::getInstance()->communicate.mtdataRouting);
    registerBehavior("processData", tag);
    requestData("requestAvg", option, "text/plain");
}

void AVGData::requestLSPData(long time)
{
//    NSArray *quoteId = [[NSString stringWithUTF8String:id.c_str()] componentsSeparatedByString:@"."];
    map<string, string> urlOption;
    urlOption.insert(pair<string, string>("exchange", "PMEC"));
    urlOption.insert(pair<string, string>("product", "AG1"));
    DataOption option = createOption(urlOption, Config::getInstance()->communicate.mtdataRouting);

    requestData("requestAvgLSP", option, "text/plain");
}

#pragma mark - 1 responseAvg
void __attribute__((annotate("oclint:suppress[long method]"))) __attribute__((annotate("oclint:suppress[high ncss method]")))AVGData::responseAvg(YTXJson::Value data, YTXJson::Value info)//datas = value["data"], info = value["Comm"];
{
    if (data.size() == 0  && info.size() == 0) {
        if (hasData()) {
            if (isNewTradeDay()) {
                clearAllData();
                fire("avgData.newTradeDay", NULL);
            }
            
            setData(lineData, dateData, kLineData, prevValue, tradedate);
            calculate();
            
        } else {
            setData(lineData, dateData, kLineData, prevValue, tradedate);
            calculate();
        }
        
        return fire("avgData.check", NULL);
        
    } else {
        if (isNewTradeDay()) {
            clearAllData();
        }
    }

    if (quotedPriceFlag && lineData.size() == 1) {
        removeLastData();
    }
//    quotedPriceFlag = false;

    YTXJson::UInt beginIndex = 0;//开始位置
    if (hasData() && data.size()>0) {
        YTXTime updatetime = YTXTime(dateData[dateData.size() - 1])-hours(8);//(quotedPriceFlag ? 2/*update , delete ...*/ : 1/*push*/)
        int newDataIndex = 0;
        int dataDataSize = (int)dateData.size() - 1;
        for (int j = 0; j < data.size(); ++j) {
            YTXJson::Value newItem = data[(YTXJson::UInt)j];
            YTXTime updateTime = YTXTime(newItem["KlTm"].asDouble());
            
            for (int i = dataDataSize; i >= 0; i--) {
                YTXTime formerTime = YTXTime(dateData[i])-hours(8);
                
                if (updateTime.toStringGMT8MMddHHmm() > formerTime.toStringGMT8MMddHHmm()) {
                    goto part2;
                } else if (updateTime.toStringGMT8MMddHHmm() == formerTime.toStringGMT8MMddHHmm()) {
                    //replace
                    double open = newItem["OpPri"].asDouble();
                    double close = newItem["ClPri"].asDouble();
                    double high = newItem["HiPri"].asDouble();
                    double low = newItem["LoPri"].asDouble();
                    double avgPri = newItem["AvPri"].asDouble();
                    double value = newItem["Tuov"].asDouble();// 总成交额
                    double volume = newItem["Vol"].asDouble();// 总成交量
                    double  hold = newItem["OpInt"].asDouble();//持仓总量
                    int index = i;//(int)(kLineData.size() - 1);//(quotedPriceFlag ? 2 : 1)
                    KLineItem & kLineItemLast = kLineData[index];
                    kLineItemLast.open = open;
                    kLineItemLast.close = close;
                    kLineItemLast.high = high;
                    kLineItemLast.low = low;
                    lineData[0][index] = close;
                    lineData[1][index] = avgPri;
                    kLineItemLast.value = value;
                    kLineItemLast.volume = volume;
                    kLineItemLast.totalHold = hold;
                    kLineItemLast.status = true;

                    newDataIndex += 1;
                    break;
                }
            }
        }
        part2://goto

        
        YTXTime updatedate = updatetime - hours(8);//本地 dateData 中最后一条数据
        
        YTXJson::Value itemElse;
        int i = (int)data.size()-1;
        beginIndex = newDataIndex;
        
        //将 beginIndex 赋值为大于 updatedate
        for (; i >=newDataIndex ; i--) {
            itemElse = data[(YTXJson::UInt)i];
            
            if (itemElse.isMember("KlTm")) {
                if (YTXTime(itemElse["KlTm"].asDouble()) > updatedate) {
                    beginIndex = i;
                } else {
                    break;
                }
            } else {
                return;
            }
        }
        
//        if (i == data.size() - 1) {//没有新数据
//            return;
//        }
    }

    
    
    double sum = 0;
    int j = 0;
    YTXJson::Int i = beginIndex;
    double high = 0, low = 0, close = 0, open = 0, volume = 0, value = 0, hold = 0, ave = 0;
    YTXTime newDataTime;
    string stringDateTime, itemTradeDate;
    double preclose = 0;
    vector<double> closeList;
    vector<double> aveList;
    vector<vector<double> >newLineData;
    vector<string> avgDate;//data中返回的时间
    YTXJson::Value item;
    std::vector<KLineItem> kLineItems;
    int len = data.size();
    itemTradeDate = info["TrdDy"].asString();
    
    for (; i < len; i++,j++) {/*把data中时间不重合的数据保存起来*/
        item = data[i];
        stringDateTime = YTXTime(item["KlTm"].asDouble()).toStringGMT8YYYYMMddHHmmss();
        newDataTime = YTXTime(stringDateTime);

        open = item["OpPri"].asDouble();
        close = item["ClPri"].asDouble();
        high = item["HiPri"].asDouble();
        low = item["LoPri"].asDouble();

        if (hasVolume) {
            volume = item["Vol"].asDouble();
            value = item["Tuov"].asDouble();
            hold = item["OpInt"].asDouble();
            ave = item["AvPri"].asDouble();
            
            aveList.push_back(ave);
        } else {
            sum += close;
            value = 0;
            volume = 0;
            
            if (item.isMember("AvPri")) {
                aveList.push_back(item["AvPri"].asDouble());
            } else {
                aveList.push_back(sum / j);
            }
        }

        KLineItem ochl = {
            itemTradeDate,
            open,
            high,
            low,
            close,
            volume,
            value,
            hold,
            newDataTime,
            0,
            0
        };
        ochl.status = 1;

        kLineItems.push_back(ochl);
        avgDate.push_back(stringDateTime);
        closeList.push_back(close);
    }

    setCloseSum(sum);
    exitDataCount = j;
    preclose = info["PreClPri"].asDouble();

    newLineData.push_back(closeList);//一分钟结算价格列表
    newLineData.push_back(aveList);//一分钟均价列表

    
    
    // 规整数据
    YTXTime firstTime = kLineItems.size()?kLineItems.front().dateTime:0;
    string indexTime,lastTime,infoKlTm;
    
    infoKlTm = YTXTime(info["KlTm"].asDouble()).toStringGMT8YYYYMMddHHmmss();
    string tempUpdateTime = dateData.size() > 0 ? dateData.back() : "0";YTXTime formerTime = YTXTime(tempUpdateTime);//YTXTime formerTime = YTXTime(Tools::parseLong(getUpdateTime())+hours(8));//
    for (int g=0, gCount = 0; g < dateRuler.size();g++) {
        
        indexTime = dateRuler[g]; newDataTime = YTXTime(indexTime);
        YTXTime currentTime = YTXTime().GMT8();
        
        if (newDataTime <= formerTime) {//info中的时间大于data中时间
            continue;
        } else if (newDataTime > currentTime) {//分时线不超过当前时间
            break;
        }
        
        if (avgDate.size()>0) {//data不为空
            lastTime = avgDate[gCount>=avgDate.size()? (avgDate.size()-1):gCount];
            
//            vector<string>::iterator s = find(dateRuler.begin(), dateRuler.end(), lastTime);//15:31 > 15:30(PT007) 问题
//            if (s == dateRuler.end()) {
//                if (kLineItems.size() && kLineItems.begin() + gCount < kLineItems.end()) {//删除数据的的必要性？
//                    kLineItems.erase(kLineItems.begin() + gCount);
//                    avgDate.erase(avgDate.begin() + gCount);
//                    closeList.erase(closeList.begin() + gCount);
//                    aveList.erase(aveList.begin() + gCount);
//                }
//                
//                continue;
//            }
        } else {
            lastTime = infoKlTm;
        }
        
        
        YTXTime lastTm  = YTXTime(lastTime);
        if (newDataTime < lastTm) {
            
            if (gCount == 0) {
                if (kLineData.size() > 0) {
                    KLineItem lastItem = getLastData();
                    
                    KLineItem ochl = {
                        currentDate,
                        lastItem.close,
                        lastItem.close,
                        lastItem.close,
                        lastItem.close,
                        0,
                        0,
                        0,
                        newDataTime,
                        0,
                        0
                    };
                    
                    kLineItems.insert(kLineItems.begin()+gCount, ochl);
                    avgDate.insert(avgDate.begin()+gCount, indexTime);
                    closeList.insert(closeList.begin()+gCount, lineData[0][lineData[0].size()-1]);
                    aveList.insert(aveList.begin()+gCount, lineData[1][lineData[1].size()-1]);
                } else {
                    KLineItem ochl = {
                        currentDate,
                        preclose,
                        preclose,
                        preclose,
                        preclose,
                        0,
                        0,
                        0,
                        newDataTime,
                        0,
                        0
                    };
                    
                    kLineItems.insert(kLineItems.begin()+gCount, ochl);
                    avgDate.insert(avgDate.begin()+gCount, indexTime);
                    closeList.insert(closeList.begin()+gCount, preclose);
                    aveList.insert(aveList.begin()+gCount, preclose);
                }
            } else {// 补中间
                if (kLineItems.size() > 0) {
                    KLineItem item = kLineItems[gCount-1];
                    KLineItem ochl = {
                        item.tradeDate = currentDate,
                        item.close,
                        item.close,
                        item.close,
                        item.close,
                        0,
                        0,
                        0,
                        newDataTime,
                        0,
                        0
                    };
                    
                    kLineItems.insert(kLineItems.begin()+gCount, ochl);
                    avgDate.insert(avgDate.begin()+gCount, indexTime);
                    closeList.insert(closeList.begin()+gCount, closeList[gCount-1]);
                    aveList.insert(aveList.begin()+gCount, aveList[gCount-1]);
                    
                } else {
                    KLineItem lastItem = getLastData();
                    KLineItem ochl = {
                        currentDate,
                        lastItem.close,
                        lastItem.close,
                        lastItem.close,
                        lastItem.close,
                        0,
                        0,
                        0,
                        newDataTime,
                        0,
                        0
                    };
                    
                    kLineItems.push_back(ochl);
                    avgDate.push_back(indexTime);
                    closeList.push_back(lineData[0][lineData[0].size()-1]);
                    aveList.push_back(lineData[1][lineData[1].size()-1]);
                }
            }
            
        } else if (newDataTime == lastTm) {
            gCount++;continue;
        } else if (newDataTime <= YTXTime(infoKlTm)) {//补 lastTIme到info中时间的数据 或 从0到info中时间的数据
            if (kLineItems.size() > 0) {
                KLineItem item = kLineItems[gCount-1];
                KLineItem ochl = {
                    item.tradeDate = currentDate,
                    item.close,
                    item.close,
                    item.close,
                    item.close,
                    0,
                    0,
                    0,
                    newDataTime,
                    0,
                    0,
                };
                
                kLineItems.insert(kLineItems.begin()+gCount, ochl);
                avgDate.insert(avgDate.begin()+gCount, indexTime);
                closeList.insert(closeList.begin()+gCount, closeList[gCount-1]);
                aveList.insert(aveList.begin()+gCount, aveList[gCount-1]);
            } else {
                KLineItem lastItem = getLastData();
                
                KLineItem ochl = {
                    currentDate,
                    lastItem.close,
                    lastItem.close,
                    lastItem.close,
                    lastItem.close,
                    0,
                    0,
                    0,
                    newDataTime,
                    0,
                    0,
                };
                
                kLineItems.push_back(ochl);
                avgDate.push_back(indexTime);
                closeList.push_back(lineData[0][lineData[0].size()-1]);
                aveList.push_back(lineData[1][lineData[1].size()-1]);
            }
        } else {
            break;
        }
        
        gCount++;
    }
    
    
    newLineData[0] = closeList;
    newLineData[1] = aveList;
    // ruler end
    
    // 交易日期
    YTXTime tradedate =  kLineItems.size()?kLineItems.back().dateTime:0;
    
//    if (avgDate.size() == 0) return;//当前时间小于交易时间
    
    string updateTime = info["KlTm"].toStyledString();//去掉结尾的”\n“
    processdata(newLineData, avgDate, kLineItems, preclose, tradedate, updateTime.substr(0,updateTime.length()-1));
    
    fire("avgData.update", NULL);
    fire("avgData.check", NULL);
    
    quotedPriceFlag = YES;
}


void __attribute__((annotate("oclint:suppress[long method]"))) __attribute__((annotate("oclint:suppress[high ncss method]")))AVGData::responseAvgLSP(YTXJson::Value data, YTXJson::Value info)
{
    YTXJson::Value item;
    string buyRatio,sellRatio,totalRatio;
    YTXTime dataTime;
    item = data;
    buyRatio = item["buyRatio"].asString();
    sellRatio = item["sellRatio"].asString();
    totalRatio = item["totalRatio"].asString();
    dataTime = YTXTime(Tools::parseLong(item["updatetime"].asString())+hours(8));
    LSPItem lsp = {
        buyRatio,
        sellRatio,
        totalRatio,
        dataTime
    };
    lspData.push_back(lsp);
}

#pragma mark - 2 updateQuotedPrice
void __attribute__((annotate("oclint:suppress[long method]")))AVGData::updateQuotedPrice(string id , string pricetime, double open, double close, double high, double low, double volume, double value, double hold, double avg){

    if (id != this->id || !this->hasData()) {
        return;
    }
    
    bool dataFlag = hasData();
    double sumValue=0, sumVolume =0, minValue, minVolume;
    vector<KLineItem>::iterator it = kLineData.begin();

    int priceTimeIntValue = Tools::parseInt(pricetime);
    YTXTime t1 = YTXTime((priceTimeIntValue/60 +(priceTimeIntValue%60==0?0:1)) * 60).GMT8();
    YTXTime t2 = YTXTime(dateData[getDataLength()-1]);//YTXTime(dateData[ dateData.size() - (quotedPriceFlag ? 2 : 1)]);
    
    if (t1 - t2 >= 120 || t2 - t1 > 0) {
        // 或者连续更新多条
        return;
    } else if (t1 - t2 >= 60) {
        quotedPriceFlag = false;//push
        
    }

    int index = 0;
    for (; it != kLineData.end(); ++it, ++index) {
        if (index  == kLineData.size()-1 && quotedPriceFlag) {
            continue;
        }
        sumVolume += (*it).volume;
        sumValue += (*it).value;
    }

    NSLog(@"TraVol-> volume:%f, value:%f", volume, value);//
    
    minVolume = MAX(volume - sumVolume, 0);
    minValue = MAX(value - sumValue, 0);
    
    vector<KLineItem> kLineItems;
    KLineItem ochl = {
        currentDate,
        open,
        high,
        low,
        close,
        minVolume,//本分钟成交量
        minValue,
        hold,
        t1,
        0,
        0,
        volume,//总成交量
        value,//总成交额
//        1,
    };
    
    ochl.status = false;
    quotedPrice = ochl;
    
    if (!dataFlag) {
        return;
    }

    if (getDataLength() == baseDrawCount || getDataLength() == baseDrawCount * 5) {
        updateLastData(this->dateData.back(), close, close, close, close, minVolume, minValue, hold, avg, volume, value);
        return fire("avgData.update", NULL);
    }

    if (quotedPriceFlag) {
        // update
        updateLastData(t1.toStringYYYYMMddHHmmss(), close, close, close, close, minVolume, minValue, hold, avg, volume, value);
    } else {
        // push
        quotedPriceFlag = true;
        vector<vector<double> > avgData;
        vector<double> price, ave;
        price.push_back(close);
        
        int dateLen = getDataLength();
        double aveValue;
        
        if (hasVolume) {
            if (std::isnan(avg)) {
                aveValue = minValue / minVolume / Metal::getAvgAccuracy(this->id);
            } else {
                aveValue = avg;
            }
        } else {
            aveValue = (lineData[1][dateLen-1]* dateLen+close) / (dateLen+1);
        }
        
        ave.push_back(aveValue);
        avgData.push_back(price);
        avgData.push_back(ave);
        vector<string> avgDate;
        avgDate.push_back(t1.toStringYYYYMMddHHmmss());
        ochl.tradeDate = t1.toStringYYYYMMddHHmmss();
        ochl.open = close;
        ochl.low = close;
        ochl.high = close;
        kLineItems.push_back(ochl);
        pushData(avgData, avgDate, kLineItems);
        fire("avgData.update", NULL);
    }
}

//bool AVGData::hasData() const
//{
//    return Quotation::hasData() || (!std::isnan(prevValue) && prevValue > 0);
//}
//
//bool AVGData::hasData(int index) const
//{
//    if(hasData()){
//        int count = lineData[0].size();
//        return count == 0 ? false : 0 <= index && index < count;
//    }
//    return  false;
//}

bool AVGData::inSameMinute(string t1, string t2){
//    ptime time1 = Tools::String2PTime(t1);
//    ptime time2 = Tools::String2PTime(t2);
//    time_duration p1 = time1.time_of_day();
//    time_duration p2 = time2.time_of_day();
//    int value = p1.total_seconds() - p2.total_seconds();
//    //没有比较日期
//    return  abs(p1.minutes() - p2.minutes()) == 0 && value < 60 && value >=1;

    YTXTime time1 = YTXTime(t1);
    YTXTime time2 = YTXTime(t2);
    YTXTime p1 = time1.time_of_day();
    YTXTime p2 = time2.time_of_day();
    long value = p1 - p2;
    //没有比较日期
    return  abs(p1.getMinute() - p2.getMinute()) == 0 && value < 60 && value >=1;
}

void AVGData::updateLastData(string pricetime, double open, double close, double high, double low, double volume, double value, double totalHold, double avg, double totalVolume, double totalValue)
{
    if (!hasData()) {
        return;
    }
    int lastIndex = getDataLength()-1;

    dateData[lastIndex] = pricetime;

    double preClose = lineData[0][lastIndex];

    lineData[0][lastIndex] = close;

    int dataLen = getDataLength();

    double ave;

    if (hasVolume) {
        if (std::isnan(avg)) {
            ave = value / volume / Metal::getAvgAccuracy(this->id);
        }
        else{
            ave = avg;
        }
    }
    else{
        ave = (lineData[1][lastIndex] * dataLen - preClose + close) / dataLen;
    }

    lineData[1][lastIndex] = ave;

//    kLineData[lastIndex].open = open;
    kLineData[lastIndex].close = close;
    kLineData[lastIndex].high = MAX(high, kLineData[lastIndex].high);
    kLineData[lastIndex].low = MIN(low, kLineData[lastIndex].low);
    kLineData[lastIndex].volume = volume;
    kLineData[lastIndex].value = value;
    kLineData[lastIndex].totalHold = totalHold;
    kLineData[lastIndex].totalVolume = totalVolume;
    kLineData[lastIndex].totalValue = totalValue;
    fire("quotedPrice.update", NULL);

}

void AVGData::updateLastDataTotalVolumeValue(double totalVolume, double totalValue) {
    if (!hasData()) {
        return;
    }
    int lastIndex = getDataLength()-1;
    kLineData[lastIndex].totalVolume = totalVolume;
    kLineData[lastIndex].totalValue = totalValue;
    fire("quotedPrice.update", NULL);
}

void AVGData::clearAllData(){
    lineData[0].clear();
    lineData[1].clear();
    dateData.clear();
    kLineData.clear();
    clearEconomicCalendarData();
    updateTime = "";
    clearUserGraphByUserDefault();
    if(prevAVGData != NULL){
        delete prevAVGData;
        prevAVGData = NULL;
    }
}

void AVGData::processdata(vector<vector<double> > & avgData, vector<string> & avgDate, vector<KLineItem> & kLineItems, double preclose, YTXTime tradedate, string updateTime)
{
    if(!avgData.size()){
        return;
    } else if (!avgDate.size()) {
        setUpdateTime(updateTime);
        return;
    }
    
    if(isPush())
    {
//        if(quotedPriceFlag){
//            removeLastData();
//            quotedPriceFlag = false;
//        }
//
        pushData(avgData, avgDate, kLineItems);

    }
    else
    {
        setData(avgData, avgDate, kLineItems, preclose, tradedate);
    }
//    string tempUpdateTime = avgDate[avgDate.size()-1];
//    string testTime = ConvertToString((YTXTime(tempUpdateTime)-hours(8)).toSeconds());
//    if (testTime < updateTime) {
//        setUpdateTime(updateTime);
//    } else {
//        setUpdateTime(testTime);
//    }
    setUpdateTime(updateTime);//avgDate[avgDate.size()-1]

    executeBehavior("processData");
}

void AVGData::setData(vector<vector<double> > & avgData, vector<string> & avgDate, vector<KLineItem> & kLineItems, double preclose, YTXTime tradedate)
{
    quotedPrice.open = std::numeric_limits<double>::quiet_NaN();
    setRow(getOriginRow());
    this->tradedate = tradedate;
    setLineData(avgData);
    setDateData(avgDate);
    setKLineData(kLineItems);
    setPrevValue(preclose);
}

void AVGData::removeLastData(){
    //    double close = lineData[0].back();
    lineData[0].pop_back();

    //    double ave = lineData[1].back();
    lineData[1].pop_back();

//    string time = dateData.back();
    dateData.pop_back();

    kLineData.pop_back();

    //    if(avgDate.size()){
    //        string newTime = avgDate[avgDate.size()-1];
    //
    //        //会发生报价的那一条 其实已经到下个点的报价了 所以需要再push过来
    //        if(inSameMinute(time, newTime)){
    //
    //            avgData[0].push_back(close);
    //            avgData[1].push_back(ave);
    //            avgDate.push_back(time);
    //        }
    //    }

}

void AVGData::pushData(vector<vector<double> > & avgData, vector<string> & avgDate, vector<KLineItem> &kLineItems )
{
//    int originLen = getDataLength();
    int newLen = (int)avgDate.size();

    if(newLen == 0){
        return;
    }

//    bool isCalculate = false;

    int  len = (int)avgData.size();

    for(int i = 0;i<len;i++)
    {
        lineData[i].insert(lineData[i].end(), avgData[i].begin(), avgData[i].end());
    }

    dateData.insert(dateData.end(), avgDate.begin(), avgDate.end());
    kLineData.insert(kLineData.end(), kLineItems.begin(), kLineItems.end());

    //缩放时可能出错
//    if(originLen != 0 && showCount != baseDrawCount && startIndex +  showCount >= newLen -1){
//        setStartIndex(startIndex + newLen);
//        isCalculate = true;
//    }

//    if(isCalculate){
//        calculate();
//    }
    calculate();
}

KLineItem AVGData::getLastData() {
    return kLineData.back();
}

void AVGData::calculateEmpty(){
    setDrawingCount(baseDrawCount);
    vector<string> nul;
    setTimeString(nul);
    setRow(getOriginRow());
    fire("load", NULL);
}

void AVGData::calculate(){
//    string end = "";
//    string begin = "";
//
//
//    if (!lineData[0].size()) {
//        return calculateEmpty();
//    }
//
//    begin = dateData[getStartIndex()];
//
//    if (getShowCount() == getBaseDrawCount()) {
//        vector<string> nul;
//        setTimeString(nul);
//        setRow(getOriginRow());
//    } else {
//        vector<string> tTimeString;
//        end = dateData[getEndIndex()-1];
//        tTimeString.push_back(begin.substr(9,5));
//        tTimeString.push_back("");
//        if(startIndex + showCount > getDataLength()){
//            tTimeString.push_back("");
//        }
//        else{
//            tTimeString.push_back(end.substr(9,5));
//        }
//        setTimeString(tTimeString);
//        setRow(Rect(2,2,2));
//    }
//    setDrawingCount(showCount);
//
//    //setLineCount(this.calculateLineType(avgDate.length - 1, this.toFix));
//    fire("load", NULL);
    if (!lineData[0].size()) {
        return calculateEmpty();
    }
    vector<string> nul;
    setTimeString(nul);
    setRow(getOriginRow());

    executeBehavior("calculate");

    fire("load", NULL);

}

bool AVGData::isPush()
{
    return getUpdateTime() != "" && lineData.size() && lineData[0].size() && !isNewTradeDay();
}

bool AVGData::isNewTradeDay()
{
    return isNewTradeDay(tradedate);
}

bool AVGData::isNewTradeDay(YTXTime time)
{
    if ( !YTXTime(currentDate).is_not_a_date_time() ) {

        if(hasData()){
            return YTXTime(currentDate) > time;
        }else{
            return false;
        }
    }
    else{
        return YES;

    }
}

bool AVGData::isInBidding()
{
    YTXTime now = YTXTime().GMT8();
    YTXTime tradeDate;
    if ( nextTradedateStartTime.is_not_a_date_time() ) {
        return false;
    }
    else {
        tradeDate = nextTradedateStartTime;

    }
    return now < tradeDate && now > tradeDate - minutes(biddingTime);
}

bool AVGData::isLessThanTradeDay(YTXTime tradedate){
//    if (hasData()){
//        tradedate += days(1);
//        if(getMarketType() != "shj"){
//            tradedate += days(1);
//        }
//
//        return ptime( tradedate.date() ) < kLineData[0].dateTime;
//    }
//    else{
//        return false;
//    }
    if (hasData()){
        tradedate += days(1);
        if(getMarketType() != "TD"){
            tradedate += days(1);
        }

        return tradedate.date() < kLineData[0].dateTime;
    }
    else{
        return false;
    }
}


bool AVGData::hasTradedate()
{
    return !tradedate.is_not_a_date_time();
}


YTXTime AVGData::fixPTimeToByAdding(YTXTime timefrom,  YTXTime timeto)
{
    if(!restTime.size()){
        return timeto;
    }

    YTXTime time_from_td = timefrom.time_of_day();
    YTXTime time_to_td = timeto.time_of_day();

    // 这里需要核查下潜在bug
    for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
        YTXTime td1 = (*it).first.time_of_day();
        YTXTime td2 = (*it).second.time_of_day();
        /* 潜在bug 没有跨天*/

        if (time_from_td <= td1 && time_to_td > td1)
        {
            time_to_td = time_to_td + (td2 - td1);
            break;
        }
    }

    return YTXTime::initByDateAndTimeOfDay(timeto.date(), time_to_td.time_of_day());
}

YTXTime AVGData::fixPTime(YTXTime time)
{
    //被废弃
    if(!restTime.size()){
        return time;
    }

    YTXTime time_td = time.time_of_day();
    // 这里需要核查下潜在bug
    for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
        YTXTime td1 = (*it).first.time_of_day();
        YTXTime td2 = (*it).second.time_of_day();
        /* 潜在bug 没有跨天*/
        if(time_td > td1 && time_td < td2){
            time_td = time_td + (td2 - td1);
        }

    }

    return YTXTime::initByDateAndTimeOfDay(time.date(), time_td.time_of_day());

}

YTXTime AVGData::updateDate(YTXTimeDuration time_duration)
{
//    ptime time1 = ptime(openTime.date(), time);
//    ptime time2 = ptime(closeTime.date(), time);
//
//    //用来计算的日期
//    if (openTime <= time1 && time1 <= closeTime ){
//        return ptime( openTime.date(), time );
//    }
//    else if(openTime <= time2 && time2 <= closeTime){
//        return ptime( closeTime.date(), time );
//    }
//    else{
//        return not_a_date_time;
//    }

    YTXTime time1 = YTXTime::initByDateAndTimeOfDay(openTime.date(), time_duration);
    YTXTime time2 = YTXTime::initByDateAndTimeOfDay(closeTime.date(), time_duration);

    //用来计算的日期
    if (openTime <= time1 && time1 <= closeTime ){
        return YTXTime::initByDateAndTimeOfDay( openTime.date(), time_duration );
    }
    else if(openTime <= time2 && time2 <= closeTime){
        return YTXTime::initByDateAndTimeOfDay( closeTime.date(), time_duration );
    }
    return YTXTime::not_a_date_time();
}

bool AVGData::inTradeTime(YTXTimeDuration time_td)
{
//    ptime time = updateDate(time_td);
//
//    if (time_td == not_a_date_time) {
//        return false;
//    }
//
//    for (vector<pair<ptime, ptime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
//        ptime & td1 = (*it).first;
//        ptime & td2 = (*it).second;
//        if ( td1 <= time && time <= td2) {
//            return false;
//        }
//
//    }
//
//    return true;


    YTXTime time = updateDate(time_td);

    if (time_td.is_not_a_date_time()) {
        return false;
    }

    for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
        YTXTime & td1 = (*it).first;
        YTXTime & td2 = (*it).second;
        if ( td1 <= time && time <= td2) {
            return false;
        }

    }

    return true;
}

bool AVGData::inTradeDate(YTXTime time){
//    ptime openDate(tradedate.date(), openTime.time_of_day());
//    ptime closeDate(nextTradedate.date(), closeTime.time_of_day());
//    if (openDate >= time || time >= closeDate) {
//        return false;
//    }
//
//    for (vector<pair<ptime, ptime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
//        ptime & td1 = (*it).first;
//        ptime & td2 = (*it).second;
//        if ( td1 <= time && time <= td2) {
//            return false;
//        }
//
//    }
//
//    return true;

    YTXTime openDate = YTXTime::initByDateAndTimeOfDay(tradedate.date(), openTime.time_of_day());
    YTXTime closeDate = YTXTime::initByDateAndTimeOfDay(nextTradedate.date(), closeTime.time_of_day());
    if (openDate >= time || time >= closeDate) {
        return false;
    }

    for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
        YTXTime & td1 = (*it).first;
        YTXTime & td2 = (*it).second;
        if ( td1 <= time && time <= td2) {
            return false;
        }

    }

    return true;
}

bool AVGData::isNewMinK(YTXTime timefrom, YTXTime timeto, int count)
{
    //countTime 数据最后条
    //lastTime 数据+周期的分钟
    if (updateTime == "") {
        return false;
    }
    else{
        timeto = fixPTimeToByAdding(timefrom, timeto);
        
        
        //当timeFrom是昨天的数据的时候，早上的分时图数据还不够大于count。就会导致false
        //所以这里可以判断个交易日
        YTXTime openTime = YTXTime::initByDateAndTimeOfDay(tradedate.date(), this->openTime.time_of_day())+hours(8); YTXTime updateTime = YTXTime(Tools::parseLong(getUpdateTime())+hours(8));
        if( openTime > timeto || ( updateTime >= timeto && getDataCountAfterTime(timefrom) >= count ) ){
            return true;
        }
    }
    return false;
}


int AVGData::getAddDay() {
    return addDay;
}

void AVGData::setAddDay(int addDay) {
    this->addDay = addDay;
}

string AVGData::getUpdateTime() {
    return updateTime;
}

void AVGData::setUpdateTime(string updateTime) {
    this->updateTime = updateTime;
}

int AVGData::getBaseDrawCount() {
    return baseDrawCount;
}

void AVGData::setBaseDrawCount(int baseDrawCount) {
    this->baseDrawCount = baseDrawCount;
}

YTXTime AVGData::getOpenTime() {
    return openTime;
}

void AVGData::setOpenTime(YTXTime openTime) {
    this->openTime = openTime;
}

YTXTime AVGData::getCloseTime(){
    return closeTime;
}

void AVGData::setCloseTime(YTXTime closeTime){
    this->closeTime = closeTime;
}

TimeString AVGData::getCalTimeString() {
    return calTimeString;
}

vector<string> & AVGData::getCalTimeString(SizeType::SizeType sizeType) {
    switch (sizeType) {
        case SizeType::small:
            return this->calTimeString.small;
        case SizeType::middle:
            return this->calTimeString.middle;
        case SizeType::big:
            return this->calTimeString.big;
    }
}

void AVGData::setCalTimeString(TimeString & calTimeString) {
    this->calTimeString = calTimeString;
}

double AVGData::getCloseSum() {
    return closeSum;
}

void AVGData::setCloseSum(double closeSum) {
    this->closeSum = closeSum;
}


AVGData * AVGData::getObservable()
{
    return this;
}

std::pair<double, double> AVGData::getAdjustedDataMinMax(int startIndex, int endIndex, const Rectangle & rect) const{
    //    if(!hasData()){
    //        return  make_pair(prevValue, prevValue);
    //    }

    double para;
    int column = rect.getColumn();

    pair<double, double> minmax = getDataMinMax(startIndex, endIndex);

    double min = minmax.first;
    double max = minmax.second;

    if(std::isnan(min) || std::isnan(max)){
        return make_pair(prevValue, prevValue);
    }

    double pv = prevValue;

    max = MAX(pv, max);

    min = MIN(pv, min);

    double v1 = abs(max-pv);
    double v2 = abs(min-pv);


    if(v1 < v2){
        v1 = v2;
    }

    para = rect.sideTextAccuracy(v1, Config::getInstance()->style.sideTextAccuracy) / (column / 2);

    if (para == 0){
        return make_pair(min * 0.99, max * 1.01);
    }

    max = pv + v1*1.3;
    min = pv - v1*1.3;


    return make_pair(min, max);
}

vector<pair<string, string> > AVGData::getTopSideText(const vector<vector<double> > & data, int index) const
{
    //值 颜色
    vector<pair<string, string> > result;
    
    if(hasData(index)){
        int i = 0;
        for (vector<string>::const_iterator it = titleType.begin(); it != titleType.begin() + 4; it += 2) {
            i = (int)(it - titleType.begin());
            string text = std::isnan(data[i==0?1:0][index]) ? "--":Tools::Convert2FixString(data[i==0?1:0][index], toFix);
            result.push_back(make_pair(titleType[i + 1] + ":" + text , titleType[i]));
        }
    }
//    if (quotationType == LineType::LAVG) {
//        string upDrop = std::isnan(data[1][index]) ? "--":Tools::Convert2FixString(data[1][index] - prevValue, toFix);
//        string percent = std::isnan(data[1][index]) ? "--%":Tools::Convert2FixString((data[1][index] - prevValue) / prevValue * 100, 2) + "%";
//        result.push_back(make_pair(upDrop, titleType[4]));
//        result.push_back(make_pair(percent, titleType[5]));
//    }
    
    
    return result;
}

vector<pair<double, string> > AVGData::getLeftSideText(int startIndex, int endIndex, const Rectangle & rect, const Style & style) const
{
    vector<pair<double, string> > sideTextList;
    string stColor = style.sideTextColor;
    double para;
    int column = rect.getColumn();
    string color = "";

    double min = rect.getMin();
    double max = rect.getMax();


    double pv = prevValue;

    if(!hasData()){
        //rect.setRectanglePara(pv, pv);
        //        for(int i =0, len = column; i<= len; i++){
        //            sideTextList.push_back(make_pair(numeric_limits<double>::quiet_NaN(), stColor));
        //        }

        for(int i = column/2; i > 0; i--){
            sideTextList.push_back(make_pair(pv - (pv * 0.01/column*2) * i, style.defaultGreen));
        }

        for(int i =1, len = column/2; i<= len; i++){
            sideTextList.push_back(make_pair(pv + (pv * 0.01/column*2) * i, style.defaultRed));
        }

        sideTextList.insert(sideTextList.begin()+ (column/2), make_pair(pv, stColor));
        return sideTextList;
    }

    max = MAX(pv, max);

    min = MIN(pv, min);

    vector<double> tempList;

    para = (max - min) / column;

    for(int i = 0, len = column / 2; i < len; i++){
        tempList.push_back( Tools::convert2Fix( min + para * i, toFix) );
    }
    tempList.push_back(pv);
    for(int i = column / 2 - 1; i >= 0; i--){
        tempList.push_back( Tools::convert2Fix( max - para * i, toFix) );
    }

    int temp = (int)((tempList.size() - 1) / 2);
    int j = 0;

    for (vector<double>::const_iterator item = tempList.begin(); item != tempList.end(); ++item, ++j)
    {
        if(j < temp)
        {
            color = style.defaultGreen;
        }
        else if(j == temp)
        {
            color = stColor;
        }
        else{
            color = style.defaultRed;
        }
        //值, 颜色
        sideTextList.push_back(make_pair(*item, color));
    }

    return sideTextList;
}



const vector<string> & AVGData::getBottomSideText(SizeType::SizeType widthType) const
{
    if(timeString.size() == 0){
        switch (widthType) {
            case SizeType::small:
                return getOriginTimeString().small;
            case SizeType::middle:
                return getOriginTimeString().middle;
            case SizeType::big:
                return getOriginTimeString().big;
        }
    }
    return timeString;
}

pair<double, double> AVGData::getDataMinMax(int startIndex, int endIndex) const
{
    auto minMax = Quotation::getDataMinMax(startIndex, endIndex);
    if (std::isnan(minMax.first)) {
        minMax.first = prevValue;
    }
    if (std::isnan(minMax.second)) {
        minMax.second = prevValue;
    }
    
    if (warningLineData.size()) {
        auto closeMinMax = getWarningLineDataCloseNowValue();
        if (closeMinMax.second != numeric_limits<double>::max()) {
            minMax.second = max(minMax.second, closeMinMax.second);
        }
        if (closeMinMax.first != numeric_limits<double>::min()) {
            minMax.first = min(minMax.first, closeMinMax.first);
        }
    }
    
    if (limitPositionInfos.size()) {
        auto orderMinMax = minmax_element(limitPositionInfos.begin(), limitPositionInfos.end(), [](LimitPositionInfo a, LimitPositionInfo b) {return get<0>(a) < get<0>(b);});
        minMax.first = min(minMax.first, get<0>(*(orderMinMax.first)));
        minMax.second = max(minMax.second, get<0>(*(orderMinMax.second)));
    }

    return minMax;

}

const std::pair<double, double> AVGData::getWarningLineDataCloseNowValue() const{
    double gt = numeric_limits<double>::max(), lt = numeric_limits<double>::min(), warningData;

    // 筛选大于多少百分比的warningLineData 不参与计算
    double nowValue = lineData[0][getDataLength()-1];

    for (std::vector<double>::const_iterator it = warningLineData.begin(); it != warningLineData.end(); ++it){
        warningData = (*it);
        if(abs(1 - warningData / nowValue) <= 0.03){ //涨跌幅小于3%
            if(warningData >= nowValue){
                gt = min(gt, warningData);
            }
            else if (warningData < nowValue){
                lt = max(lt, warningData);
            }
        }
    }

    return make_pair(lt, gt);
}

int AVGData::getDataCountBetweenTime(YTXTime time1, YTXTime time2)
{
    int count = 0;
    for (vector<string>::reverse_iterator it = dateData.rbegin(); it != dateData.rend(); ++it) {
        YTXTime now = YTXTime((*it));
        if( now > time1 and now <= time2){
            count++;
        }
    }
    return count;
}



int AVGData::getDataCountAfterTime(YTXTime time1)
{
    int count = 0;
    for (vector<string>::reverse_iterator it = dateData.rbegin(); it != dateData.rend(); ++it) {
        YTXTime now = YTXTime((*it));
        if( now > time1){
            count++;
        }
        else{
            break;
        }
    }
    return count;
}

KLineItem AVGData::getOCHL(double preClose){
    return getOCHL(0, preClose);
}

KLineItem AVGData::getOCHL(int startIndex, double preClose){
    return getOCHL(startIndex, (int)dateData.size(), preClose);
}

bool compareForMax(KLineItem item1, KLineItem item2){
    return Tools::compareForMax(item1.high, item2.high);
}

bool compareForMin(KLineItem item1, KLineItem item2){
    return Tools::compareForMin(item1.low, item2.low);
}


KLineItem AVGData::getOCHL(int startIndex, int endIndex, double preClose)
{
    if (!hasData()) {
        KLineItem nilItem = {currentDate, numeric_limits<double>::quiet_NaN() };
        return nilItem;
    }

    double open = numeric_limits<double>::quiet_NaN(), close = numeric_limits<double>::quiet_NaN();
    KLineItem exitsKLineItem;
    vector<KLineItem>::iterator it = kLineData.begin() + startIndex;
    open = it->open;
    exitsKLineItem = *it;

    if(std::isnan(open)){
        KLineItem nilItem = {currentDate, numeric_limits<double>::quiet_NaN() };
        return nilItem;
    }

    KLineItem & item = kLineData.back();
    close = item.close;
    
    if(std::isnan(preClose)){
        preClose = close;
    }

    //如果最后一条是报价，则最高和最低不能用
    //    int tempIndex = ((endIndex == getDataLength()) && quotedPriceFlag) ? (endIndex - 1) : endIndex;

    double high = exitsKLineItem.high, low = exitsKLineItem.low;
    double value = 0,volume = 0;
    endIndex = (int)MIN(endIndex, kLineData.size() - 1);
    for (vector<KLineItem>::iterator it = kLineData.begin() + startIndex; it != kLineData.begin() + endIndex + 1; ++it) {
        low = MIN(low, it->low);
        high = MAX(high, it->high);
        
        value += it->value;
        volume += it->volume;
//        NSLog(@"++++++++++++++++++++%f------%f", it->volume, it->totalVolume);
    }
    
//    double oldTotalVolume = 0;
//    for (vector<KLineItem>::iterator it = kLineData.begin(); it != kLineData.begin() + startIndex; ++it) {
//        
//        if (YTXTime(currentDate) < it->dateTime) {
//            oldTotalVolume += it->volume;
//        }
//    }

//    KLineItem beginItem = *(kLineData.begin() + startIndex);
//    KLineItem beginItemFront = {currentDate, numeric_limits<double>::quiet_NaN() };
//    if (startIndex >= 1) {
//        beginItemFront = *(kLineData.begin() + startIndex - 1);
//    }
    
    KLineItem endItem = *((kLineData.begin() + endIndex == kLineData.end()) ? kLineData.end()-1 : (kLineData.begin() + endIndex));

    KLineItem ochl = {
        currentDate,
        open,
        high,
        low,
        close,
        volume,
        value,
        endItem.totalHold,
        endItem.dateTime,//YTXTime(dateData[endIndex - 1]),
        close - preClose,
        (close / preClose - 1) * 100,
        volume,//debug
        value//debug
    };

    return ochl;
}

KLineItem AVGData::getOCHL(YTXTime limitTime, double preClose){
    int startIndex = (int)dateData.size();
    //反向遍历
    for (vector<string>::reverse_iterator it = dateData.rbegin(); it != dateData.rend(); ++it) {
        if(YTXTime((*it)) >= limitTime ){
            startIndex = (int)(dateData.size() - (it - dateData.rbegin()) - 1);
        }
        else{
            break;
        }
    }

    return getOCHL(startIndex, preClose);
}

KLineItem AVGData::getOCHLBySnapShort(YTXTime limitTime, double preClose){
    if(!std::isnan(quotedPrice.open)){
        //KLineItem snapShort = kLineData[getDataLength()-1];
        double open = quotedPrice.open;
        double close = quotedPrice.close;
        double high = quotedPrice.high;
        double low = quotedPrice.low;
        YTXTime time = quotedPrice.dateTime;
        double volume = quotedPrice.volume;
        double value = quotedPrice.value;
        double hold = quotedPrice.totalHold;
        double totalVolume = quotedPrice.totalVolume;//NEW(debug)
        double totalValue = quotedPrice.totalValue;//NEW(debug)
        double change = close - preClose;
        if(std::isnan(preClose)){
            preClose = close;
        }
        double percent = (close / preClose - 1 ) * 100;

        KLineItem ochl = {
            currentDate,
            open,
            high,
            low,
            close,
            volume,
            value,
            hold,
            time,
            change,
            percent,
            totalVolume,
            totalValue
        };
        return ochl;
    }

    int startIndex = (int)dateData.size();
    //反向遍历
    for (vector<string>::reverse_iterator it = dateData.rbegin(); it != dateData.rend(); ++it) {
        if(YTXTime((*it)) >= limitTime ){
            startIndex = (int)(dateData.size() - (it - dateData.rbegin()) - 1);
        }
        else{
            break;
        }
    }

    return getOCHL(startIndex, preClose);
}

KLineItem AVGData::getOCHL(YTXTime limitTime1, YTXTime limitTime2, double preClose){
    KLineItem nilItem = {currentDate, numeric_limits<double>::quiet_NaN() };

    if(!hasData()){
        return nilItem;
    }

    int startIndex = -1;
    // 要排除最后一根 如果是报价

    int endIndex = (int)dateData.size();
    //    - (quotedPriceFlag ? 2: 1);
    vector<string>::iterator endIt = dateData.end();
    //    - (quotedPriceFlag ? 1 : 0);
    //反向遍历

    limitTime2 = fixPTimeToByAdding(limitTime1, limitTime2);

    for (vector<string>::iterator it = dateData.begin(); it != endIt; ++it) {
        YTXTime now = YTXTime((*it));
        if( now > limitTime1 && now < limitTime2){
            startIndex = (int)(it - dateData.begin());
            break;
        }
    }

    if(startIndex == -1){
        KLineItem ret = {currentDate, numeric_limits<double>::quiet_NaN() };
        return ret;
    }
    for (vector<string>::iterator it = dateData.begin() + startIndex; it != endIt; ++it) {
        YTXTime now = YTXTime((*it));
        if( now >= limitTime1 and now < limitTime2){
            endIndex = (int)(it - dateData.begin()+1);
        }
        else{
            break;
        }
    }
    return getOCHL(startIndex, endIndex, preClose);
}

double AVGData::getCrosshairXValue(int index)
{
    if(hasData(index)){
        return lineData[0][index];
    }
    return 0;
}

void AVGData::responsePrevData(YTXJson::Value datas, YTXJson::Value info)
{
    prevAVGData = new AVGData(this);

    prevAVGData->responseAvg(datas, info);
    
    executeBehavior("responsePrevData");

    fire("prevAVGData.load", NULL);
}

void AVGData::getPrevAVGData(int count)
{
    if (!prevAVGData || !prevAVGData->hasData() || prevAVGData->dateData.size() != count * baseDrawCount) {
        
        registerBehavior("responsePrevData", "calculate");
        
        map<string, string> urlOption;
        urlOption.insert(pair<string, string>("Ei", id));
        urlOption.insert(pair<string, string>("DayNum", ConvertToString(count)));
        DataOption option = createOption(urlOption, Config::getInstance()->communicate.hisDaysKdataRouting);
        
        requestData("requestPrevData", option, "text/plain");
    }
    
}

void AVGData::behaviorFactory(std::string taskName)
{
    if (taskName =="calculate") {
        calculate();
    }
    else if(taskName == "getPrevAVGData"){
        getPrevAVGData();
    }
}

YTXTime AVGData::getTradedate()
{
    return tradedate;
}


const vector<vector<double> > AVGData::getLineDataWhateverEmpty(double prevValue)
{
    if(hasData()){
        return lineData;
    }
    vector<vector<double> > tLineData;
    tLineData.push_back(vector<double>(baseDrawCount, prevValue));
    tLineData.push_back(vector<double>(baseDrawCount, prevValue));
    return tLineData;
}

const vector<KLineItem> AVGData::getKLineDataWhateverEmpty(double prevValue){
    if(hasData()){
        return kLineData;
    }
    KLineItem ochl = {
        currentDate,
        prevValue,
        prevValue,
        prevValue,
        prevValue,
        0,
        0,
        0,
        //CHECK: ptime()
        YTXTime::not_a_date_time(),
        0,
        0
    };
    vector<KLineItem> tLineData(baseDrawCount, ochl);
    return tLineData;
}

const vector<string> AVGData::getDateDataWhateverEmpty()
{
    if(hasData()){
        return dateData;
    }
    //要做为空的处理
    vector<string> tData(baseDrawCount, "");
    return tData;
}


bool AVGData::todayIsFinish()
{
    int len = getDataLength();

    return len >= baseDrawCount;

}

void AVGData::calculateIfHasData()
{
    if(hasData())
    {
        calculate();
    }
}

void AVGData::cleanData()
{
    quotedPrice.open = std::numeric_limits<double>::quiet_NaN();
//    quotedPriceFlag = false;

    SAFEDELETE(prevAVGData);

    Quotation::cleanData();
}



bool AVGData::addWarningLineData(double value){
    int index = indexOf(warningLineData, value);
    if ( index == -1) {
        warningLineData.push_back(value);
        return true;
    }
    return false;
}

bool AVGData::removeWarningLineData(double value){
    int index = indexOf(warningLineData, value);
    if(index > -1){
        warningLineData.erase(warningLineData.begin()+index);
        return true;
    }
    return false;
}

bool AVGData::updateWarningLineData(vector<double> value){
    warningLineData = value;
    return true;
}


const std::vector<EconomicCalendarData> AVGData::getEconomicCalendarDataList() const{
    return economicCalendarDataList;
}

void AVGData::setEconomicCalendarDataWithoutValid(vector<EconomicCalendarData> economicCalendarDataList)
{
    this->economicCalendarDataList = economicCalendarDataList;
}

void AVGData::addEconomicCalendarData(EconomicCalendarData economicCalendarData){
    for (std::vector<EconomicCalendarData>::const_iterator it = economicCalendarDataList.begin(); it != economicCalendarDataList.end(); ++it){
        if (economicCalendarData.ecTime == (*it).ecTime) {
            return;
        }
    }
    if ( !hasTradedate() || !inTradeDate(economicCalendarData.ecTime)){
        return;
    }

    economicCalendarDataList.push_back(economicCalendarData);
}

void AVGData::addEconomicCalendarDataList(vector<EconomicCalendarData> economicCalendarDataList){
    for (std::vector<EconomicCalendarData>::const_iterator it = economicCalendarDataList.begin(); it != economicCalendarDataList.end(); ++it){
        addEconomicCalendarData((*it));
    }
}

void AVGData::removeEconomicCalendarData(EconomicCalendarData economicCalendarData){
    for (std::vector<EconomicCalendarData>::iterator it = economicCalendarDataList.begin(); it != economicCalendarDataList.end(); ++it){
        if (economicCalendarData.ecTime == (*it).ecTime) {
            economicCalendarDataList.erase(it);
        }
    }
}

void AVGData::requestEconomicCalendarDataList()
{
    if  ( economicCalendarDataFlag || economicCalendarDataList.size() > 0 || !YTXConfig::getInstance()->AVG.isDrawEconomicCalendarBanner){
        return;
    }
    map<string, string> urlOption;

    YTXTime openDate =  YTXTime::initByDateAndTimeOfDay(tradedate.date(), openTime.time_of_day())-hours(8);
    YTXTime closeDate = YTXTime::initByDateAndTimeOfDay(nextTradedate.date(), closeTime.time_of_day())-hours(8);

    //CHECK:
    //    string beginDateString = ConvertToString( Tools::ptime2MilliSecondsSinceEpoch(  Tools::quoteServerPTimeToGMT00( openDate ) ));
    //    string endDateString = ConvertToString( Tools::ptime2MilliSecondsSinceEpoch( Tools::quoteServerPTimeToGMT00( closeDate ) ));
    
    string beginDateString = ConvertToString( openDate.getCurrentTimeToMillisecond() );
    string endDateString = ConvertToString( closeDate.getCurrentTimeToMillisecond() );


    urlOption.insert(pair<string, string>("beginDate", beginDateString));
    urlOption.insert(pair<string, string>("endDate", endDateString));
    urlOption.insert(pair<string, string>("top", "1"));
    Communicate com = Config::getInstance()->communicate;
    DataOption option = DataOption(urlOption, "", com.financialCalendarUrl);
    //TODO("去掉财经日历");
    requestData("requestEconomicCalendarDataList", option, "application/json");


}

void AVGData::responseEconomicCalendarDataList(YTXJson::Value data)
{
    if(economicCalendarDataFlag){
        return;
    }
    //时区转东8
    economicCalendarDataFlag = true;

    for (YTXJson::Value::iterator it = data.begin(); it != data.end(); ++it) {
        YTXJson::Value item = (*it);
        EconomicCalendarData economicCalendarData;
        //这个和ecTime是一致的
        if (item.isMember("id")) {
            economicCalendarData.dataId = item["id"].asInt();
        }
        if (item.isMember("publishTimeMs")) {
            //CHECK: GMT0 economicCalendarData.ecTime = Tools::milliSecond2PTimeGMT08(item["publishTimeMs"].asDouble());
            economicCalendarData.ecTime = YTXTime(item["publishTimeMs"].asDouble()/1000)+hours(8);
        }
        if (item.isMember("ecTitle")) {
            economicCalendarData.ecTitle = item["ecTitle"].asString();
        }
        if (item.isMember("ecName")) {
            economicCalendarData.ecName = item["ecName"].asString();
        }
        if (item.isMember("ecCountry")) {
            economicCalendarData.ecCountry = item["ecCountry"].asString();
        }
        if (item.isMember("ecFormerValue")) {
            economicCalendarData.ecFormerValue = item["ecFormerValue"].asString();
        }
        if (item.isMember("ecPredictedValue")) {
            economicCalendarData.ecPredictedValue = item["ecPredictedValue"].asString();
        }
        if (item.isMember("ecPublishedValue")) {
            economicCalendarData.ecPublishedValue = item["ecPublishedValue"].asString();
        }
        YTXJson::FastWriter fastWriter;
        economicCalendarData.json = fastWriter.write(item);
        addEconomicCalendarData(economicCalendarData);

    }
    fire("economicCalendarData.load", NULL);
    calculate();
}

void AVGData::clearEconomicCalendarData(){
    economicCalendarDataFlag = false;
    economicCalendarDataList.clear();
}

YTXTimeDuration AVGData::getTimeDurationByIndex(size_t dataIndex)
{
    YTXTime time = YTXTime::not_a_date_time();

    if (dataIndex < drawingCount) {
        int mins = 0;

        for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
            YTXTime td1 = (*it).first;
            YTXTime td2 = (*it).second;

            YTXTime difference = (td2-td1);
            mins += difference.getHour() * 60 + difference.getMinute();
        }

        time = openTime;
        time += minutes((int)dataIndex+mins);
    }

    return time.time_of_day();
}

const int AVGData::getIndexByTimeDuration(YTXTimeDuration time_td){
    int startIndex = 0;
    //两日分的话 得往后推
    if(getDrawingCount() > getBaseDrawCount()){
        startIndex = getDrawingCount() - getBaseDrawCount();
    }
    if (inTradeTime(time_td)) {

        if (time_td.is_not_a_date_time()) {
            return -1;
        }

        YTXTime time = updateDate(time_td);

        int mins = 0;
        for (vector<pair<YTXTime, YTXTime> >::iterator it = restTime.begin(); it != restTime.end(); ++it) {
            YTXTime td1 = (*it).first;
            YTXTime td2 = (*it).second;
            if(time < td1){
                break;
            }
            YTXTime difference = (td2-td1);
            mins += difference.getHour() * 60 + difference.getMinute();

        }
        YTXTime difference = (time - openTime);
        int index = difference.getHour() * 60 + difference.getMinute() - mins;

        return index+startIndex;
    }
    return -1;
}

UGCPoint AVGData::getUserGraphWithPoint(float x1, float y1, Rectangle rect)
{
    UGCPoint point;
    point.dataY = rect.getValueY(y1);
    if (drawingCount == baseDrawCount * 2) {
        //两日分
        point.dataIndexX = rect.getViewIndexByPX(x1);
    }
    else {
        //分时
        point.dataIndexX = drawingCount+rect.getViewIndexByPX(x1);
    }
    return point;
}

void AVGData::setBuyPoint(double buyPoint)
{
    this->buyPoints.assign(1, buyPoint);
}

void AVGData::clearBuyPoints()
{
    this->buyPoints.clear();
}

list<double> AVGData::getBuyPoints() const
{
    return this->buyPoints;
}

#pragma mark - Limit Position Infos

void AVGData::setLimitPositionInfos(const std::list<LimitPositionInfo> &limitPositionInfos)
{
    this->limitPositionInfos = limitPositionInfos;
}

void AVGData::addLimitPositionInfo(const LimitPositionInfo &limitPositionInfo)
{
    this->limitPositionInfos.push_back(limitPositionInfo);
}

void AVGData::clearLimitPositionInfos()
{
    this->limitPositionInfos.clear();
}

const std::list<LimitPositionInfo> & AVGData::getLimitPositionInfos() const
{
    return this->limitPositionInfos;
}
